/*************************************************************
* Strip Packing Problem
* 
*
* */
#ifndef HEURISTICA_H
#define HEURISTICA_H

   #include <iostream>
   #include <fstream>
   #include <string>
   #include <list>
   #include "rectangulo.h"
   #include <vector>

   #include "solucion.h"

   #define MAX_ITERACIONES 500
   #define MAX_ITERACIONES_SIN_CAMBIO 100
   
   using namespace std;

   /** Clase Heurística:
    *    La idea es dejar esta clase como padre y derivar las distintas
    *    heurísticas a partir de esta. Podríamos implementar aquí las
    *    funciones comunes, como las reglas de parada, y en las clases
    *    hija las no comunes, como la actualización de la solución.
    *    
    * */
   class Heuristica {
      protected:
         
         /** Solución que se le pasa a contenedor para que calcule la altura */
         list<Rectangulo>  solucion;
         
         /** Listado de todos los rectángulos */
         list<Rectangulo>  candidatos;
         
         /** Listado de la mejor solucion */
         list<Rectangulo>  mejor;
         
         /** Valor de la mejor solución */
         int mejorSol;
         
         /** Iteración actual.
          *  Útil para el criterio de parada. Hay que aumentarla cada vez
          *  que se llame a mejorarSolucion, así que no se olviden de ponerla dentro
          *  No sé si existe otro método para hacerlo automático
          * */
         int iteracion;
         int iteracionSinCambio;
         
      public:

         /**
         * Constructor por defecto. 
         * En principio no se usa.
         * */
         Heuristica();
         
         ~Heuristica();

         /** Constructor
         * @param listado de los rectángulos a empaquetar
         * */
         Heuristica(list<Rectangulo> lista_in);

         /**
          * Reinicia la solucion.
          * Vacia la lista solucion y pone los rectangulos
          * en la lista candidatos para empezar de nuevo.
          * */
         void reiniciaSolucion();
         
         
         /**
         * Muestra lista de solucion.
         * */
         void muestraSolucion();

         /**
         * Muestra lista de candidatos
         * */
         void muestraCandidatos();

         /**
         * Cambia un rectangulo de la lista solucion a la lista candidatos
         * @param iterator de list<Rectangulo> con el elemento a mover
         * */
         void aCandidatos(list<Rectangulo>::iterator itOrigen);

         /**
         * Cambia un rectangulo de la lista candidatos a la lista solucion
         * @param iteratot de list<Rectangulo> con el elemento a mover
         * */
         void aSolucion(list<Rectangulo>::iterator & itOrigen);

         /** 
         * Generar solución inicial 
         * Mecanismo de generación de soluciones iniciales
         * • Soluciones generadas aleatoriamente
         * • GRASP
         * • Soluciones distantes de los óptimos locales previamente encontrados
         * */
         virtual list<Rectangulo> generaInicial();




         /** 
         * Modificar la solución 
         * 
         * • Búsqueda local
         * • Estructura de entorno
         * • Muestreo en el entorno
         * */
         virtual list<Rectangulo> mejoraSolucion();


            
         /** 
         * Condición de parada 
         * 
         * Regla de parada, posibles implementaciones:
         *  Número máximo de iteraciones (o número máximo de soluciones visitadas)
         *  Tiempo máximo de CPU
         *  Número máximo de iteraciones sin mejora
         *  Análisis estadístico
         *  Número de óptimos locales distintos
         *  Valores objetivos de los óptimos locales
         *  Número de iteraciones para encontrar el óptimo local
         * */
         virtual bool parada(int valor);
         
      /**
       * Devuelve el valor de la mejor solución
       * */
       int getMejorH();
       list<Rectangulo> getMejorSol();

       int getIteracion();
       int getIteracionSinCambio();
       
       
        vector<Solucion> generaConjuntoSoluciones(int S);
       
      /**
       * Combina dos Soluciones a partir del elemento posicion y respetando o no el giro
       * @param origen Solucion a imitar
       * @param destino Solucion que imita
       * @param posicion elemento hasta el que se copia de origen a destino
       * @param giro indica si se imita el giro del origen (1), del destino(-1), o no se modifica (0)
       * */ 
      Solucion combinaSoluciones(Solucion & origen, Solucion & destino, int posicion, int giro);
      
      /* Intercambia dos rectángulos al azar y los gira con una probabilidad del 50%
      @param Solución a mutar
      @return Nueva solución mutada.
      */
      Solucion MutarSolucion(Solucion & s);
      
      void intercambiaRectangulo(int id1, int id2, list<Rectangulo> & lista, bool rotar);
      void intercambiaRectangulo(list<Rectangulo>:: iterator it1, list<Rectangulo>:: iterator it2, list<Rectangulo> & lista);

  };

#endif
